/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */


const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;

Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");

Cu.import("resource://savefileto/common.jsm");
Cu.import("resource://savefileto/constants.jsm");
Cu.import("resource://savefileto/DataSource.jsm");
Cu.import("resource://savefileto/Entry.jsm");
Cu.import("resource://savefileto/savefileto.jsm");
Cu.import("resource://savefileto/Transformer.jsm");

const clipboard = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
const dragSvc = Cc["@mozilla.org/widget/dragservice;1"].getService(Ci.nsIDragService);


const FLAVOR_SAVEFILETO_INDEXES = "application/x.org.mozdev.savefileto.indexes";  // rfc 4288
const FLAVOR_SAVEFILETO_ENTRIES = "application/x.org.mozdev.savefileto.entries";  // rfc 4288


var prefwindow =
{
    panes: ["main"].concat(TYPES),
    
    /** current prefpane name (prefwindow.panes) */
    pane: null,
    
    _treeView: {},
    
    get mode()      { return document.documentElement.getAttribute("mode"); },
    set mode(value) { return document.documentElement.setAttribute("mode", value); },
    
    get toggleModeButton() { return document.documentElement.getButton("extra2"); },
    
    /** current type */
    get type()
    {
        var pane = this.pane;
        return ((TYPES.indexOf(pane) != -1) ? pane : null);
    },
    
    /** is current type enabled */
    get enabled()
    {
        var type = this.type;
        return (type ? this.isEnabled(type) : false);
    },
    
    /** current type's tree view */
    get treeView()
    {
        var type = this.type;
        return (type ? this._treeView[type] : null);
    },
    
    onLoad: function()
    {
        this._ = new StringBundle("chrome://savefileto/locale/prefwindow.properties").getter;
        this.prefs = Services.prefs.getBranch(EXT_PREF_BRANCH);
        
        var self = this;
        var instantApply = document.documentElement.instantApply;
        
        for each (var type in TYPES)
        {
            // data source
            let prefName = EXT_PREF_BRANCH + type + ".entries";
            let dataSource = this._createDataSource(type, instantApply);
            
            // tree view
            let tree = document.getElementById("tree_" + type + "_entries");
            let treeView = new DataSourceTreeView(dataSource, window);
            tree.view = this._treeView[type] = treeView;
            
            // tree controller
            let controller = new TreeController(treeView);
            tree.controllers.appendController(controller);
            
            // tree drag'n'drop
            let dnd = new TreeDragAndDrop(tree, treeView);
            treeView.dnd = dnd;
            
            // tree splitter resize
            tree.addEventListener("command", function(e) { self.onTreeCommand(e); }, false);
        }
        
        // entry controller
        var controller = new EntryController();
        window.controllers.appendController(controller);
        
        // prefpane select listener
        document.documentElement._selector.addEventListener("select", function(e) { self.onPaneSelect(e); }, false);
        
        // mode
        this.toggleModeButton.addEventListener("command", function() { self.toggleMode(); }, false);
        this._updateMode();
        
        this.pane = this._resolvePaneFromElement(document.documentElement.currentPane);
        this._updateUi(this.pane);
        
        // don't know why, but update doesn't work until a delay
        // goUpdateCommand() can't seem to find the controller the first time
        // the first call is still done to disable all the commands to avoid flicker
        this._updateCommands();
        callLater(0, this, this._updateCommands);
    },
    
    toggleMode: function()
    {
        this.mode = ((this.mode != "simple") ? "simple" : "advanced");
        this._updateMode();
    },
    
    onDialogAccept: function()
    {
        for each (var type in TYPES)
            this._treeView[type].dataSource.flush();
        
        return true;
    },
    
    onPaneSelect: function(e)
    {
        var node = e.originalTarget;
        var pane = this.panes[node.selectedIndex];
        
        this.pane = pane;
        this._updateUi(this.pane);
        this._updateCommands();
    },
    
    onTypeEnabledChange: function(e)
    {
        var pref = e.target;
        var type = this._resolvePaneFromElement(pref);
        var enabled = this.isEnabled(type);
        
        if (! enabled)
            this._treeView[type].clearSelection();
        
        this._updateUi(type);
        
        if (type == this.type)
            this._updateCommands();
    },
    
    onTreeCommand: function(e)
    {
        if (e.target.nodeName == "splitter")
            this._updateTreeColumnWidths();
    },
    
    onTreeSelect: function(e)
    {
        this._updateCommands();
    },
    
    onTreeKeyPress: function(e)
    {
        if (e.charCode == e.DOM_VK_SPACE)
            goDoCommand("cmd_toggleMenu");
    },
    
    onTreeDoubleClick: function(e)
    {
        var result = this.treeView.getCellAt(e.clientX, e.clientY);
        var col = result.col;
        
        if (col && (this.treeView.getColumnType(col) != "menu"))
            goDoCommand("cmd_editEntry");
    },
    
    isEnabled: function(type)
    {
        var pref = document.getElementById("pref_" + type + "_enabled");
        return (pref ? pref.value : false);
    },
    
    clearRecent: function()
    {
        savefileto.cleanUp(true);
    },
    
    /**
     * Creates caching data source.
     */
    _createDataSource: function(type, writeThrough)
    {
        var mainDataSource = savefileto.mainDataSource[type];
        
        var transformers =
        {
            folder: null,
            item: savefileto.commandLabelTransformer,
            named: savefileto.namedFolderTransformer,
            recent: null,
            separator: null
        }
        var transformer =
            new ArrayTransformer(
                new SwitchTransformer("type", transformers),
                true);
        
        var dataSource =
            new CachingDataSource(
                new TransformingDataSource(mainDataSource, transformer),
                writeThrough);
        
        return dataSource;
    },
    
    _resolvePaneFromElement: function(elem)
    {
        var id = elem.id;
        var start = id.indexOf("_");
        var end = id.indexOf("_", start + 1);
        if (end == -1)
            end = id.length;
        var type = id.substring(start + 1, end);
        return type;
    },
    
    _updateMode: function()
    {
        let mode = this.mode;
        let isAdvanced = (mode == "advanced");
        
        this.toggleModeButton.setAttribute("mode", mode);
        this.toggleModeButton.label = this._("mode." + mode);
        this.toggleModeButton.hidden = false;
        
        let width = this._("mode.css.width");
        if (width != "-1")
            this.toggleModeButton.style.width = width;
    },
    
    _updateUi: function(pane)
    {
        if (TYPES.indexOf(pane) != -1)
        {
            var type = pane;
            var enabled = this.isEnabled(type);
            
            document.getElementById("tree_" + type + "_entries").disabled = (! enabled);
            document.getElementById("btn_" + type + "_addEntry").disabled = (! enabled);
        }
    },
    
    _updateTreeColumnWidths: function()
    {
        let widths = [];
        let columns = this.treeView.treeBoxObject.columns;
        for (let i = 0; i < columns.length; i++)
            widths.push(columns[i].element.width);
        
        for each (let type in TYPES)
        {
            columns = this._treeView[type].treeBoxObject.columns;
            for (let i = 0; i < columns.length; i++)
                columns[i].element.width = widths[i];
        }
    },
    
    _updateCommands: function()
    {
        window.updateCommands("tree-select");
    }
}
